#pragma once

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <vector>

using namespace std;

static const int N = 16;

template <class T>

class RingQueue{
private:
    void P(sem_t &s){
        sem_wait(&s);
    }

    void V(sem_t &s){
        sem_post(&s);
    }

public:
    RingQueue(int num = N) : _ring(num), _cap(num){
        sem_init(&_dataSem, 0, 0);
        sem_init(&_spaceSem, 0, num);
        _cStep = _pStep = 0;
    }

    void push(const T &in){
        P(_spaceSem);
        _ring[_pStep++] = in;
        _pStep %= _cap;
        V(_dataSem);
    }

    void pop(T *out){
        P(_dataSem);
        *out = _ring[_cStep++];
        _cStep %= _cap;
        V(_spaceSem);
    }

    ~RingQueue(){
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);
    }

private:
    vector<T> _ring;
    int _cap;
    sem_t _dataSem;
    sem_t _spaceSem;
    int _cStep;
    int _pStep;
};